/*
 * Dealer.java
 *
 * Copyright(c) 2011 - Kimnach
 * See Main.java for copyright notice.
 *
 */

package main.control;

import java.awt.Color;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Random;
import main.model.Player;

/**
 * Initiative dealer. Takes list of players and shuffles for order.
 * Also handles removing and adding of players and keeping track of dead players.
 * @author dkimnach
 */
public class Dealer {

    private ArrayList<Player> deck;

    private Random random  = new Random();
    private int    counter = 0;
    
    private HashMap<Integer, ArrayList<Player>> history;
    
    /**
     * Default constructor, constructs an empty list of players
     */
    public Dealer () {
        deck    = new ArrayList<Player>();
        history = new HashMap<Integer, ArrayList<Player>>();
    }

    /**
     * Constructs the list of players from array of players passed in
     * @param players ArrayList of players to construct from
     */
    public Dealer (ArrayList<Player> players) {
        deck    = new ArrayList<Player>(players);
        history = new HashMap<Integer, ArrayList<Player>>();
    }

    /**
     * Constructs the list of players from array of players passed in set to a specific counter
     * @param players ArrayList of players to construct from
     */
    public Dealer (ArrayList<Player> players, int counter) {
        deck    = new ArrayList<Player>(players);
        history = new HashMap<Integer, ArrayList<Player>>();

        this.counter = counter;
    }

    /**
     * Shuffles list of players, ignoring all dead players
     * @return shuffled deck
     */
    public ArrayList<Player> deal () {
        ArrayList<Player> dead = new ArrayList<Player>();

        history.put(counter + 1, deck);

        for (int i = 0; i < deck.size(); i++) {
            Player p = deck.get(i);

            if (p.isDead()) {
                deck.remove(i);
                dead.add(p);

                i--; // size of list is now less one
            }
        }
        deck.trimToSize();

        Collections.shuffle(deck, random);

        deck.addAll(dead);
        dead.clear();

        System.out.println("New initiatives dealt");

        counter++;

        return deck;
    }

    /**
     * Switches initiatives (positions in list) with two players (numbers are indexes and start at 0)
     * @param thisone first index to swap with second
     * @param thatone second index to swap with first
     */
    public void planB (int thisone, int thatone) {
        if (thisone != thatone) {
            System.out.println(deck.get(thisone).getName() + " for " + deck.get(thatone).getName());

            Collections.swap(deck, thisone, thatone);
        }
    }

    /**
     * Returns current order of players
     * @return current deck
     */
    public ArrayList<Player> getDeck () {
        System.out.println("Getting list");
        return deck;
    }

    /**
     * Move player at [index] to the last index of the list
     * @param index player to move
     * @return index of last position
     */
    public int moveToBottom (int index) {
        int last = deck.size() - 1;
        int pos  = 0;

        do {
            if (pos == 0 && !deck.get(last).isDead()) {
                Player p = deck.remove(index);

                deck.add(p);

                System.out.println("Moving " + p.getName() + " to bottom");
                break;
            }
            else if (!deck.get(last - pos).isDead()) {
                Player p = deck.remove(index);

                deck.add((last - pos), p);

                System.out.println("Moving " + p.getName() + " to bottom");
                break;
            }
            pos++;
        }
        while (pos <= last);

        return last - pos;
    }

    /**
     * Move player at [index] to the first index of the list (0)
     * @param index player to move
     * @return index of first position (0)
     */
    public int moveToTop (int index) {
        Player p = deck.remove(index);

        deck.add(0, p);

        System.out.println("Moving " + p.getName() + " to top");
        return 0;
    }

    /**
     * Kill player at [index] (move to bottom and mark dead)
     * @param index player index to kill
     * @return index of last position
     */
    public int killPlayer (int index) {
        int    pos  = moveToBottom(index);
        Player p    = deck.get(pos);

        System.out.println(p.getName() + " dies");

        p.die();

        deck.set(pos, p);
        return pos;
    }

    /**
     * Revive a player that was killed (unmark as dead).  Looks up dead player by color rather than name (allows players with same name)
     * @param col color of player that died (if you need to undo it)
     * @return player index that was revived
     */
    public int revive (Color col) {
        int index = -1;

        for (int i = 0; i < deck.size(); i++) {
            Player p = deck.get(i);

            if (p.getColor().equals(col)) {
                System.out.println(p.getName() + " revived");

                p.revive();

                deck.set(i, p);

                index = i;
            }
        }
        return index;
    }

    /**
     * Returns current count of deals
     * @return counter
     */
    public int getCounter () {
        return counter;
    }

    /**
     * set the counter of deals to a number
     * @param count number to set deals to
     */
    public void setCounter (int count) {
        counter = count;
    }

    @Override
    public String toString () {
        String s = "Deck contents: \n";

        for (Player p : deck) {
            s += p.getName() + " - " + p.isDead() + "\n";
        }

        s += counter + " deals called\n";

        return s;
    }

    /**
     * remove a player from play
     * @param col color of player
     */
    public void removePlayer (Color col) {
        for (int i = 0; i < deck.size(); i++) {
            Player p = deck.get(i);

            if (p.getColor().equals(col)) {
                System.out.println(p.getName() + " removed");
                deck.remove(i);
            }
        }
        deck.trimToSize();
    }

    /**
     * rename a player
     * @param col color of player
     * @param name new name of player
     */
    public Boolean renamePlayer (Color col, String name) {
        Boolean found = false;

        for (int i = 0; i < deck.size(); i++) {
            Player p = deck.get(i);

            if (p.getColor().equals(col)) {
                if (!p.getName().equals(name)) {
                    System.out.println(p.getName() + " renamed to " + name);

                    p.setName(name);

                    deck.set(i, p);
                }

                found = true;
                break;
            }
        }

        return found;
    }

    /**
     * add a player
     * @param name name of player
     * @param col color of player
     */
    public void addPlayer (String name, Color col) {
        deck.add(new Player(name, col));
        deck.trimToSize();
    }

    /**
     * start a new game, clearing everything
     */
    public void newGame () {
        deck.clear();

        counter = 0;
    }
}
